home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / intl / dcigettext.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-19  |  33.2 KB  |  1,260 lines

  1. /* Implementation of the internal dcigettext function.
  2.    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify it
  5.    under the terms of the GNU Library General Public License as published
  6.    by the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.    Library General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU Library General Public
  15.    License along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17.    USA.  */
  18.  
  19. /* Tell glibc's <string.h> to provide a prototype for mempcpy().
  20.    This must come before <config.h> because <config.h> may include
  21.    <features.h>, and once <features.h> has been included, it's too late.  */
  22. #ifndef _GNU_SOURCE
  23. # define _GNU_SOURCE    1
  24. #endif
  25.  
  26. #ifdef HAVE_CONFIG_H
  27. # include <config.h>
  28. #endif
  29.  
  30. #include <sys/types.h>
  31.  
  32. #ifdef __GNUC__
  33. # define alloca __builtin_alloca
  34. # define HAVE_ALLOCA 1
  35. #else
  36. # if defined HAVE_ALLOCA_H || defined _LIBC
  37. #  include <alloca.h>
  38. # else
  39. #  ifdef _AIX
  40.  #pragma alloca
  41. #  else
  42. #   ifndef alloca
  43. char *alloca ();
  44. #   endif
  45. #  endif
  46. # endif
  47. #endif
  48.  
  49. #include <errno.h>
  50. #ifndef errno
  51. extern int errno;
  52. #endif
  53. #ifndef __set_errno
  54. # define __set_errno(val) errno = (val)
  55. #endif
  56.  
  57. #include <stddef.h>
  58. #include <stdlib.h>
  59.  
  60. #include <string.h>
  61. #if !HAVE_STRCHR && !defined _LIBC
  62. # ifndef strchr
  63. #  define strchr index
  64. # endif
  65. #endif
  66.  
  67. #if defined HAVE_UNISTD_H || defined _LIBC
  68. # include <unistd.h>
  69. #endif
  70.  
  71. #include <locale.h>
  72.  
  73. #if defined HAVE_SYS_PARAM_H || defined _LIBC
  74. # include <sys/param.h>
  75. #endif
  76.  
  77. #include "gettextP.h"
  78. #ifdef _LIBC
  79. # include <libintl.h>
  80. #else
  81. # include "libgnuintl.h"
  82. #endif
  83. #include "hash-string.h"
  84.  
  85. /* Thread safetyness.  */
  86. #ifdef _LIBC
  87. # include <bits/libc-lock.h>
  88. #else
  89. /* Provide dummy implementation if this is outside glibc.  */
  90. # define __libc_lock_define_initialized(CLASS, NAME)
  91. # define __libc_lock_lock(NAME)
  92. # define __libc_lock_unlock(NAME)
  93. # define __libc_rwlock_define_initialized(CLASS, NAME)
  94. # define __libc_rwlock_rdlock(NAME)
  95. # define __libc_rwlock_unlock(NAME)
  96. #endif
  97.  
  98. /* Alignment of types.  */
  99. #if defined __GNUC__ && __GNUC__ >= 2
  100. # define alignof(TYPE) __alignof__ (TYPE)
  101. #else
  102. # define alignof(TYPE) \
  103.     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
  104. #endif
  105.  
  106. /* The internal variables in the standalone libintl.a must have different
  107.    names than the internal variables in GNU libc, otherwise programs
  108.    using libintl.a cannot be linked statically.  */
  109. #if !defined _LIBC
  110. # define _nl_default_default_domain _nl_default_default_domain__
  111. # define _nl_current_default_domain _nl_current_default_domain__
  112. # define _nl_default_dirname _nl_default_dirname__
  113. # define _nl_domain_bindings _nl_domain_bindings__
  114. #endif
  115.  
  116. /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
  117. #ifndef offsetof
  118. # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
  119. #endif
  120.  
  121. /* @@ end of prolog @@ */
  122.  
  123. #ifdef _LIBC
  124. /* Rename the non ANSI C functions.  This is required by the standard
  125.    because some ANSI C functions will require linking with this object
  126.    file and the name space must not be polluted.  */
  127. # define getcwd __getcwd
  128. # ifndef stpcpy
  129. #  define stpcpy __stpcpy
  130. # endif
  131. # define tfind __tfind
  132. #else
  133. # if !defined HAVE_GETCWD
  134. char *getwd ();
  135. #  define getcwd(buf, max) getwd (buf)
  136. # else
  137. char *getcwd ();
  138. # endif
  139. # ifndef HAVE_STPCPY
  140. static char *stpcpy PARAMS ((char *dest, const char *src));
  141. # endif
  142. # ifndef HAVE_MEMPCPY
  143. static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
  144. # endif
  145. #endif
  146.  
  147. /* Amount to increase buffer size by in each try.  */
  148. #define PATH_INCR 32
  149.  
  150. /* The following is from pathmax.h.  */
  151. /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
  152.    PATH_MAX but might cause redefinition warnings when sys/param.h is
  153.    later included (as on MORE/BSD 4.3).  */
  154. #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
  155. # include <limits.h>
  156. #endif
  157.  
  158. #ifndef _POSIX_PATH_MAX
  159. # define _POSIX_PATH_MAX 255
  160. #endif
  161.  
  162. #if !defined PATH_MAX && defined _PC_PATH_MAX
  163. # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
  164. #endif
  165.  
  166. /* Don't include sys/param.h if it already has been.  */
  167. #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
  168. # include <sys/param.h>
  169. #endif
  170.  
  171. #if !defined PATH_MAX && defined MAXPATHLEN
  172. # define PATH_MAX MAXPATHLEN
  173. #endif
  174.  
  175. #ifndef PATH_MAX
  176. # define PATH_MAX _POSIX_PATH_MAX
  177. #endif
  178.  
  179. /* Pathname support.
  180.    ISSLASH(C)           tests whether C is a directory separator character.
  181.    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
  182.                         it may be concatenated to a directory pathname.
  183.    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
  184.  */
  185. #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
  186.   /* Win32, OS/2, DOS */
  187. # define ISSLASH(C) ((C) == '/' || (C) == '\\')
  188. # define HAS_DEVICE(P) \
  189.     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
  190.      && (P)[1] == ':')
  191. # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
  192. # define IS_PATH_WITH_DIR(P) \
  193.     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
  194. #else
  195.   /* Unix */
  196. # define ISSLASH(C) ((C) == '/')
  197. # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
  198. # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
  199. #endif
  200.  
  201. /* XPG3 defines the result of `setlocale (category, NULL)' as:
  202.    ``Directs `setlocale()' to query `category' and return the current
  203.      setting of `local'.''
  204.    However it does not specify the exact format.  Neither do SUSV2 and
  205.    ISO C 99.  So we can use this feature only on selected systems (e.g.
  206.    those using GNU C Library).  */
  207. #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
  208. # define HAVE_LOCALE_NULL
  209. #endif
  210.  
  211. /* This is the type used for the search tree where known translations
  212.    are stored.  */
  213. struct known_translation_t
  214. {
  215.   /* Domain in which to search.  */
  216.   char *domainname;
  217.  
  218.   /* The category.  */
  219.   int category;
  220.  
  221.   /* State of the catalog counter at the point the string was found.  */
  222.   int counter;
  223.  
  224.   /* Catalog where the string was found.  */
  225.   struct loaded_l10nfile *domain;
  226.  
  227.   /* And finally the translation.  */
  228.   const char *translation;
  229.   size_t translation_length;
  230.  
  231.   /* Pointer to the string in question.  */
  232.   char msgid[ZERO];
  233. };
  234.  
  235. /* Root of the search tree with known translations.  We can use this
  236.    only if the system provides the `tsearch' function family.  */
  237. #if defined HAVE_TSEARCH || defined _LIBC
  238. # include <search.h>
  239.  
  240. static void *root;
  241.  
  242. # ifdef _LIBC
  243. #  define tsearch __tsearch
  244. # endif
  245.  
  246. /* Function to compare two entries in the table of known translations.  */
  247. static int transcmp PARAMS ((const void *p1, const void *p2));
  248. static int
  249. transcmp (p1, p2)
  250.      const void *p1;
  251.      const void *p2;
  252. {
  253.   const struct known_translation_t *s1;
  254.   const struct known_translation_t *s2;
  255.   int result;
  256.  
  257.   s1 = (const struct known_translation_t *) p1;
  258.   s2 = (const struct known_translation_t *) p2;
  259.  
  260.   result = strcmp (s1->msgid, s2->msgid);
  261.   if (result == 0)
  262.     {
  263.       result = strcmp (s1->domainname, s2->domainname);
  264.       if (result == 0)
  265.     /* We compare the category last (though this is the cheapest
  266.        operation) since it is hopefully always the same (namely
  267.        LC_MESSAGES).  */
  268.     result = s1->category - s2->category;
  269.     }
  270.  
  271.   return result;
  272. }
  273. #endif
  274.  
  275. /* Name of the default domain used for gettext(3) prior any call to
  276.    textdomain(3).  The default value for this is "messages".  */
  277. const char _nl_default_default_domain[] = "messages";
  278.  
  279. /* Value used as the default domain for gettext(3).  */
  280. const char *_nl_current_default_domain = _nl_default_default_domain;
  281.  
  282. /* Contains the default location of the message catalogs.  */
  283. const char _nl_default_dirname[] = LOCALEDIR;
  284.  
  285. /* List with bindings of specific domains created by bindtextdomain()
  286.    calls.  */
  287. struct binding *_nl_domain_bindings;
  288.  
  289. /* Prototypes for local functions.  */
  290. static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
  291.                     unsigned long int n,
  292.                     const char *translation,
  293.                     size_t translation_len))
  294.      internal_function;
  295. static unsigned long int plural_eval PARAMS ((struct expression *pexp,
  296.                           unsigned long int n))
  297.      internal_function;
  298. static const char *category_to_name PARAMS ((int category)) internal_function;
  299. static const char *guess_category_value PARAMS ((int category,
  300.                          const char *categoryname))
  301.      internal_function;
  302.  
  303.  
  304. /* For those loosing systems which don't have `alloca' we have to add
  305.    some additional code emulating it.  */
  306. #ifdef HAVE_ALLOCA
  307. /* Nothing has to be done.  */
  308. # define ADD_BLOCK(list, address) /* nothing */
  309. # define FREE_BLOCKS(list) /* nothing */
  310. #else
  311. struct block_list
  312. {
  313.   void *address;
  314.   struct block_list *next;
  315. };
  316. # define ADD_BLOCK(list, addr)                              \
  317.   do {                                          \
  318.     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
  319.     /* If we cannot get a free block we cannot add the new element to          \
  320.        the list.  */                                  \
  321.     if (newp != NULL) {                                  \
  322.       newp->address = (addr);                              \
  323.       newp->next = (list);                              \
  324.       (list) = newp;                                  \
  325.     }                                          \
  326.   } while (0)
  327. # define FREE_BLOCKS(list)                              \
  328.   do {                                          \
  329.     while (list != NULL) {                              \
  330.       struct block_list *old = list;                          \
  331.       list = list->next;                              \
  332.       free (old);                                  \
  333.     }                                          \
  334.   } while (0)
  335. # undef alloca
  336. # define alloca(size) (malloc (size))
  337. #endif    /* have alloca */
  338.  
  339.  
  340. #ifdef _LIBC
  341. /* List of blocks allocated for translations.  */
  342. typedef struct transmem_list
  343. {
  344.   struct transmem_list *next;
  345.   char data[ZERO];
  346. } transmem_block_t;
  347. static struct transmem_list *transmem_list;
  348. #else
  349. typedef unsigned char transmem_block_t;
  350. #endif
  351.  
  352.  
  353. /* Names for the libintl functions are a problem.  They must not clash
  354.    with existing names and they should follow ANSI C.  But this source
  355.    code is also used in GNU C Library where the names have a __
  356.    prefix.  So we have to make a difference here.  */
  357. #ifdef _LIBC
  358. # define DCIGETTEXT __dcigettext
  359. #else
  360. # define DCIGETTEXT dcigettext__
  361. #endif
  362.  
  363. /* Lock variable to protect the global data in the gettext implementation.  */
  364. #ifdef _LIBC
  365. __libc_rwlock_define_initialized (, _nl_state_lock)
  366. #endif
  367.  
  368. /* Checking whether the binaries runs SUID must be done and glibc provides
  369.    easier methods therefore we make a difference here.  */
  370. #ifdef _LIBC
  371. # define ENABLE_SECURE __libc_enable_secure
  372. # define DETERMINE_SECURE
  373. #else
  374. # ifndef HAVE_GETUID
  375. #  define getuid() 0
  376. # endif
  377. # ifndef HAVE_GETGID
  378. #  define getgid() 0
  379. # endif
  380. # ifndef HAVE_GETEUID
  381. #  define geteuid() getuid()
  382. # endif
  383. # ifndef HAVE_GETEGID
  384. #  define getegid() getgid()
  385. # endif
  386. static int enable_secure;
  387. # define ENABLE_SECURE (enable_secure == 1)
  388. # define DETERMINE_SECURE \
  389.   if (enable_secure == 0)                              \
  390.     {                                          \
  391.       if (getuid () != geteuid () || getgid () != getegid ())              \
  392.     enable_secure = 1;                              \
  393.       else                                      \
  394.     enable_secure = -1;                              \
  395.     }
  396. #endif
  397.  
  398. /* Look up MSGID in the DOMAINNAME message catalog for the current
  399.    CATEGORY locale and, if PLURAL is nonzero, search over string
  400.    depending on the plural form determined by N.  */
  401. char *
  402. DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
  403.      const char *domainname;
  404.      const char *msgid1;
  405.      const char *msgid2;
  406.      int plural;
  407.      unsigned long int n;
  408.      int category;
  409. {
  410. #ifndef HAVE_ALLOCA
  411.   struct block_list *block_list = NULL;
  412. #endif
  413.   struct loaded_l10nfile *domain;
  414.   struct binding *binding;
  415.   const char *categoryname;
  416.   const char *categoryvalue;
  417.   char *dirname, *xdomainname;
  418.   char *single_locale;
  419.   char *retval;
  420.   size_t retlen;
  421.   int saved_errno;
  422. #if defined HAVE_TSEARCH || defined _LIBC
  423.   struct known_translation_t *search;
  424.   struct known_translation_t **foundp = NULL;
  425.   size_t msgid_len;
  426. #endif
  427.   size_t domainname_len;
  428.  
  429.   /* If no real MSGID is given return NULL.  */
  430.   if (msgid1 == NULL)
  431.     return NULL;
  432.  
  433.   __libc_rwlock_rdlock (_nl_state_lock);
  434.  
  435.   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
  436.      CATEGORY is not LC_MESSAGES this might not make much sense but the
  437.      definition left this undefined.  */
  438.   if (domainname == NULL)
  439.     domainname = _nl_current_default_domain;
  440.  
  441. #if defined HAVE_TSEARCH || defined _LIBC
  442.   msgid_len = strlen (msgid1) + 1;
  443.  
  444.   /* Try to find the translation among those which we found at
  445.      some time.  */
  446.   search = (struct known_translation_t *)
  447.        alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
  448.   memcpy (search->msgid, msgid1, msgid_len);
  449.   search->domainname = (char *) domainname;
  450.   search->category = category;
  451.  
  452.   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
  453.   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
  454.     {
  455.       /* Now deal with plural.  */
  456.       if (plural)
  457.     retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
  458.                 (*foundp)->translation_length);
  459.       else
  460.     retval = (char *) (*foundp)->translation;
  461.  
  462.       __libc_rwlock_unlock (_nl_state_lock);
  463.       return retval;
  464.     }
  465. #endif
  466.  
  467.   /* Preserve the `errno' value.  */
  468.   saved_errno = errno;
  469.  
  470.   /* See whether this is a SUID binary or not.  */
  471.   DETERMINE_SECURE;
  472.  
  473.   /* First find matching binding.  */
  474.   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
  475.     {
  476.       int compare = strcmp (domainname, binding->domainname);
  477.       if (compare == 0)
  478.     /* We found it!  */
  479.     break;
  480.       if (compare < 0)
  481.     {
  482.       /* It is not in the list.  */
  483.       binding = NULL;
  484.       break;
  485.     }
  486.     }
  487.  
  488.   if (binding == NULL)
  489.     dirname = (char *) _nl_default_dirname;
  490.   else if (IS_ABSOLUTE_PATH (binding->dirname))
  491.     dirname = binding->dirname;
  492.   else
  493.     {
  494.       /* We have a relative path.  Make it absolute now.  */
  495.       size_t dirname_len = strlen (binding->dirname) + 1;
  496.       size_t path_max;
  497.       char *ret;
  498.  
  499.       path_max = (unsigned int) PATH_MAX;
  500.       path_max += 2;        /* The getcwd docs say to do this.  */
  501.  
  502.       for (;;)
  503.     {
  504.       dirname = (char *) alloca (path_max + dirname_len);
  505.       ADD_BLOCK (block_list, dirname);
  506.  
  507.       __set_errno (0);
  508.       ret = getcwd (dirname, path_max);
  509.       if (ret != NULL || errno != ERANGE)
  510.         break;
  511.  
  512.       path_max += path_max / 2;
  513.       path_max += PATH_INCR;
  514.     }
  515.  
  516.       if (ret == NULL)
  517.     {
  518.       /* We cannot get the current working directory.  Don't signal an
  519.          error but simply return the default string.  */
  520.       FREE_BLOCKS (block_list);
  521.       __libc_rwlock_unlock (_nl_state_lock);
  522.       __set_errno (saved_errno);
  523.       return (plural == 0
  524.           ? (char *) msgid1
  525.           /* Use the Germanic plural rule.  */
  526.           : n == 1 ? (char *) msgid1 : (char *) msgid2);
  527.     }
  528.  
  529.       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
  530.     }
  531.  
  532.   /* Now determine the symbolic name of CATEGORY and its value.  */
  533.   categoryname = category_to_name (category);
  534.   categoryvalue = guess_category_value (category, categoryname);
  535.  
  536.   domainname_len = strlen (domainname);
  537.   xdomainname = (char *) alloca (strlen (categoryname)
  538.                  + domainname_len + 5);
  539.   ADD_BLOCK (block_list, xdomainname);
  540.  
  541.   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
  542.           domainname, domainname_len),
  543.       ".mo");
  544.  
  545.   /* Creating working area.  */
  546.   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
  547.   ADD_BLOCK (block_list, single_locale);
  548.  
  549.  
  550.   /* Search for the given string.  This is a loop because we perhaps
  551.      got an ordered list of languages to consider for the translation.  */
  552.   while (1)
  553.     {
  554.       /* Make CATEGORYVALUE point to the next element of the list.  */
  555.       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
  556.     ++categoryvalue;
  557.       if (categoryvalue[0] == '\0')
  558.     {
  559.       /* The whole contents of CATEGORYVALUE has been searched but
  560.          no valid entry has been found.  We solve this situation
  561.          by implicitly appending a "C" entry, i.e. no translation
  562.          will take place.  */
  563.       single_locale[0] = 'C';
  564.       single_locale[1] = '\0';
  565.     }
  566.       else
  567.     {
  568.       char *cp = single_locale;
  569.       while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
  570.         *cp++ = *categoryvalue++;
  571.       *cp = '\0';
  572.  
  573.       /* When this is a SUID binary we must not allow accessing files
  574.          outside the dedicated directories.  */
  575.       if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
  576.         /* Ingore this entry.  */
  577.         continue;
  578.     }
  579.  
  580.       /* If the current locale value is C (or POSIX) we don't load a
  581.      domain.  Return the MSGID.  */
  582.       if (strcmp (single_locale, "C") == 0
  583.       || strcmp (single_locale, "POSIX") == 0)
  584.     {
  585.       FREE_BLOCKS (block_list);
  586.       __libc_rwlock_unlock (_nl_state_lock);
  587.       __set_errno (saved_errno);
  588.       return (plural == 0
  589.           ? (char *) msgid1
  590.           /* Use the Germanic plural rule.  */
  591.           : n == 1 ? (char *) msgid1 : (char *) msgid2);
  592.     }
  593.  
  594.  
  595.       /* Find structure describing the message catalog matching the
  596.      DOMAINNAME and CATEGORY.  */
  597.       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
  598.  
  599.       if (domain != NULL)
  600.     {
  601.       retval = _nl_find_msg (domain, binding, msgid1, &retlen);
  602.  
  603.       if (retval == NULL)
  604.         {
  605.           int cnt;
  606.  
  607.           for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
  608.         {
  609.           retval = _nl_find_msg (domain->successor[cnt], binding,
  610.                      msgid1, &retlen);
  611.  
  612.           if (retval != NULL)
  613.             {
  614.               domain = domain->successor[cnt];
  615.               break;
  616.             }
  617.         }
  618.         }
  619.  
  620.       if (retval != NULL)
  621.         {
  622.           /* Found the translation of MSGID1 in domain DOMAIN:
  623.          starting at RETVAL, RETLEN bytes.  */
  624.           FREE_BLOCKS (block_list);
  625.           __set_errno (saved_errno);
  626. #if defined HAVE_TSEARCH || defined _LIBC
  627.           if (foundp == NULL)
  628.         {
  629.           /* Create a new entry and add it to the search tree.  */
  630.           struct known_translation_t *newp;
  631.  
  632.           newp = (struct known_translation_t *)
  633.             malloc (offsetof (struct known_translation_t, msgid)
  634.                 + msgid_len + domainname_len + 1);
  635.           if (newp != NULL)
  636.             {
  637.               newp->domainname =
  638.             mempcpy (newp->msgid, msgid1, msgid_len);
  639.               memcpy (newp->domainname, domainname, domainname_len + 1);
  640.               newp->category = category;
  641.               newp->counter = _nl_msg_cat_cntr;
  642.               newp->domain = domain;
  643.               newp->translation = retval;
  644.               newp->translation_length = retlen;
  645.  
  646.               /* Insert the entry in the search tree.  */
  647.               foundp = (struct known_translation_t **)
  648.             tsearch (newp, &root, transcmp);
  649.               if (foundp == NULL
  650.               || __builtin_expect (*foundp != newp, 0))
  651.             /* The insert failed.  */
  652.             free (newp);
  653.             }
  654.         }
  655.           else
  656.         {
  657.           /* We can update the existing entry.  */
  658.           (*foundp)->counter = _nl_msg_cat_cntr;
  659.           (*foundp)->domain = domain;
  660.           (*foundp)->translation = retval;
  661.           (*foundp)->translation_length = retlen;
  662.         }
  663. #endif
  664.           /* Now deal with plural.  */
  665.           if (plural)
  666.         retval = plural_lookup (domain, n, retval, retlen);
  667.  
  668.           __libc_rwlock_unlock (_nl_state_lock);
  669.           return retval;
  670.         }
  671.     }
  672.     }
  673.   /* NOTREACHED */
  674. }
  675.  
  676.  
  677. char *
  678. internal_function
  679. _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
  680.      struct loaded_l10nfile *domain_file;
  681.      struct binding *domainbinding;
  682.      const char *msgid;
  683.      size_t *lengthp;
  684. {
  685.   struct loaded_domain *domain;
  686.   size_t act;
  687.   char *result;
  688.   size_t resultlen;
  689.  
  690.   if (domain_file->decided == 0)
  691.     _nl_load_domain (domain_file, domainbinding);
  692.  
  693.   if (domain_file->data == NULL)
  694.     return NULL;
  695.  
  696.   domain = (struct loaded_domain *) domain_file->data;
  697.  
  698.   /* Locate the MSGID and its translation.  */
  699.   if (domain->hash_size > 2 && domain->hash_tab != NULL)
  700.     {
  701.       /* Use the hashing table.  */
  702.       nls_uint32 len = strlen (msgid);
  703.       nls_uint32 hash_val = hash_string (msgid);
  704.       nls_uint32 idx = hash_val % domain->hash_size;
  705.       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
  706.  
  707.       while (1)
  708.     {
  709.       nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
  710.  
  711.       if (nstr == 0)
  712.         /* Hash table entry is empty.  */
  713.         return NULL;
  714.  
  715.       /* Compare msgid with the original string at index nstr-1.
  716.          We compare the lengths with >=, not ==, because plural entries
  717.          are represented by strings with an embedded NUL.  */
  718.       if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
  719.           && (strcmp (msgid,
  720.               domain->data + W (domain->must_swap,
  721.                         domain->orig_tab[nstr - 1].offset))
  722.           == 0))
  723.         {
  724.           act = nstr - 1;
  725.           goto found;
  726.         }
  727.  
  728.       if (idx >= domain->hash_size - incr)
  729.         idx -= domain->hash_size - incr;
  730.       else
  731.         idx += incr;
  732.     }
  733.       /* NOTREACHED */
  734.     }
  735.   else
  736.     {
  737.       /* Try the default method:  binary search in the sorted array of
  738.      messages.  */
  739.       size_t top, bottom;
  740.  
  741.       bottom = 0;
  742.       top = domain->nstrings;
  743.       while (bottom < top)
  744.     {
  745.       int cmp_val;
  746.  
  747.       act = (bottom + top) / 2;
  748.       cmp_val = strcmp (msgid, (domain->data
  749.                     + W (domain->must_swap,
  750.                      domain->orig_tab[act].offset)));
  751.       if (cmp_val < 0)
  752.         top = act;
  753.       else if (cmp_val > 0)
  754.         bottom = act + 1;
  755.       else
  756.         goto found;
  757.     }
  758.       /* No translation was found.  */
  759.       return NULL;
  760.     }
  761.  
  762.  found:
  763.   /* The translation was found at index ACT.  If we have to convert the
  764.      string to use a different character set, this is the time.  */
  765.   result = ((char *) domain->data
  766.         + W (domain->must_swap, domain->trans_tab[act].offset));
  767.   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
  768.  
  769. #if defined _LIBC || HAVE_ICONV
  770.   if (domain->codeset_cntr
  771.       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
  772.     {
  773.       /* The domain's codeset has changed through bind_textdomain_codeset()
  774.      since the message catalog was initialized or last accessed.  We
  775.      have to reinitialize the converter.  */
  776.       _nl_free_domain_conv (domain);
  777.       _nl_init_domain_conv (domain_file, domain, domainbinding);
  778.     }
  779.  
  780.   if (
  781. # ifdef _LIBC
  782.       domain->conv != (__gconv_t) -1
  783. # else
  784. #  if HAVE_ICONV
  785.       domain->conv != (iconv_t) -1
  786. #  endif
  787. # endif
  788.       )
  789.     {
  790.       /* We are supposed to do a conversion.  First allocate an
  791.      appropriate table with the same structure as the table
  792.      of translations in the file, where we can put the pointers
  793.      to the converted strings in.
  794.      There is a slight complication with plural entries.  They
  795.      are represented by consecutive NUL terminated strings.  We
  796.      handle this case by converting RESULTLEN bytes, including
  797.      NULs.  */
  798.  
  799.       if (domain->conv_tab == NULL
  800.       && ((domain->conv_tab = (char **) calloc (domain->nstrings,
  801.                             sizeof (char *)))
  802.           == NULL))
  803.     /* Mark that we didn't succeed allocating a table.  */
  804.     domain->conv_tab = (char **) -1;
  805.  
  806.       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
  807.     /* Nothing we can do, no more memory.  */
  808.     goto converted;
  809.  
  810.       if (domain->conv_tab[act] == NULL)
  811.     {
  812.       /* We haven't used this string so far, so it is not
  813.          translated yet.  Do this now.  */
  814.       /* We use a bit more efficient memory handling.
  815.          We allocate always larger blocks which get used over
  816.          time.  This is faster than many small allocations.   */
  817.       __libc_lock_define_initialized (static, lock)
  818. # define INITIAL_BLOCK_SIZE    4080
  819.       static unsigned char *freemem;
  820.       static size_t freemem_size;
  821.  
  822.       const unsigned char *inbuf;
  823.       unsigned char *outbuf;
  824.       int malloc_count;
  825. # ifndef _LIBC
  826.       transmem_block_t *transmem_list = NULL;
  827. # endif
  828.  
  829.       __libc_lock_lock (lock);
  830.  
  831.       inbuf = (const unsigned char *) result;
  832.       outbuf = freemem + sizeof (size_t);
  833.  
  834.       malloc_count = 0;
  835.       while (1)
  836.         {
  837.           transmem_block_t *newmem;
  838. # ifdef _LIBC
  839.           size_t non_reversible;
  840.           int res;
  841.  
  842.           if (freemem_size < sizeof (size_t))
  843.         goto resize_freemem;
  844.  
  845.           res = __gconv (domain->conv,
  846.                  &inbuf, inbuf + resultlen,
  847.                  &outbuf,
  848.                  outbuf + freemem_size - sizeof (size_t),
  849.                  &non_reversible);
  850.  
  851.           if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
  852.         break;
  853.  
  854.           if (res != __GCONV_FULL_OUTPUT)
  855.         {
  856.           __libc_lock_unlock (lock);
  857.           goto converted;
  858.         }
  859.  
  860.           inbuf = result;
  861. # else
  862. #  if HAVE_ICONV
  863.           const char *inptr = (const char *) inbuf;
  864.           size_t inleft = resultlen;
  865.           char *outptr = (char *) outbuf;
  866.           size_t outleft;
  867.  
  868.           if (freemem_size < sizeof (size_t))
  869.         goto resize_freemem;
  870.  
  871.           outleft = freemem_size - sizeof (size_t);
  872.           if (iconv (domain->conv,
  873.              (ICONV_CONST char **) &inptr, &inleft,
  874.              &outptr, &outleft)
  875.           != (size_t) (-1))
  876.         {
  877.           outbuf = (unsigned char *) outptr;
  878.           break;
  879.         }
  880.           if (errno != E2BIG)
  881.         {
  882.           __libc_lock_unlock (lock);
  883.           goto converted;
  884.         }
  885. #  endif
  886. # endif
  887.  
  888.         resize_freemem:
  889.           /* We must allocate a new buffer or resize the old one.  */
  890.           if (malloc_count > 0)
  891.         {
  892.           ++malloc_count;
  893.           freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
  894.           newmem = (transmem_block_t *) realloc (transmem_list,
  895.                              freemem_size);
  896. # ifdef _LIBC
  897.           if (newmem != NULL)
  898.             transmem_list = transmem_list->next;
  899.           else
  900.             {
  901.               struct transmem_list *old = transmem_list;
  902.  
  903.               transmem_list = transmem_list->next;
  904.               free (old);
  905.             }
  906. # endif
  907.         }
  908.           else
  909.         {
  910.           malloc_count = 1;
  911.           freemem_size = INITIAL_BLOCK_SIZE;
  912.           newmem = (transmem_block_t *) malloc (freemem_size);
  913.         }
  914.           if (__builtin_expect (newmem == NULL, 0))
  915.         {
  916.           freemem = NULL;
  917.           freemem_size = 0;
  918.           __libc_lock_unlock (lock);
  919.           goto converted;
  920.         }
  921.  
  922. # ifdef _LIBC
  923.           /* Add the block to the list of blocks we have to free
  924.                  at some point.  */
  925.           newmem->next = transmem_list;
  926.           transmem_list = newmem;
  927.  
  928.           freemem = newmem->data;
  929.           freemem_size -= offsetof (struct transmem_list, data);
  930. # else
  931.           transmem_list = newmem;
  932.           freemem = newmem;
  933. # endif
  934.  
  935.           outbuf = freemem + sizeof (size_t);
  936.         }
  937.  
  938.       /* We have now in our buffer a converted string.  Put this
  939.          into the table of conversions.  */
  940.       *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
  941.       domain->conv_tab[act] = (char *) freemem;
  942.       /* Shrink freemem, but keep it aligned.  */
  943.       freemem_size -= outbuf - freemem;
  944.       freemem = outbuf;
  945.       freemem += freemem_size & (alignof (size_t) - 1);
  946.       freemem_size = freemem_size & ~ (alignof (size_t) - 1);
  947.  
  948.       __libc_lock_unlock (lock);
  949.     }
  950.  
  951.       /* Now domain->conv_tab[act] contains the translation of all
  952.      the plural variants.  */
  953.       result = domain->conv_tab[act] + sizeof (size_t);
  954.       resultlen = *(size_t *) domain->conv_tab[act];
  955.     }
  956.  
  957.  converted:
  958.   /* The result string is converted.  */
  959.  
  960. #endif /* _LIBC || HAVE_ICONV */
  961.  
  962.   *lengthp = resultlen;
  963.   return result;
  964. }
  965.  
  966.  
  967. /* Look up a plural variant.  */
  968. static char *
  969. internal_function
  970. plural_lookup (domain, n, translation, translation_len)
  971.      struct loaded_l10nfile *domain;
  972.      unsigned long int n;
  973.      const char *translation;
  974.      size_t translation_len;
  975. {
  976.   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
  977.   unsigned long int index;
  978.   const char *p;
  979.  
  980.   index = plural_eval (domaindata->plural, n);
  981.   if (index >= domaindata->nplurals)
  982.     /* This should never happen.  It means the plural expression and the
  983.        given maximum value do not match.  */
  984.     index = 0;
  985.  
  986.   /* Skip INDEX strings at TRANSLATION.  */
  987.   p = translation;
  988.   while (index-- > 0)
  989.     {
  990. #ifdef _LIBC
  991.       p = __rawmemchr (p, '\0');
  992. #else
  993.       p = strchr (p, '\0');
  994. #endif
  995.       /* And skip over the NUL byte.  */
  996.       p++;
  997.  
  998.       if (p >= translation + translation_len)
  999.     /* This should never happen.  It means the plural expression
  1000.        evaluated to a value larger than the number of variants
  1001.        available for MSGID1.  */
  1002.     return (char *) translation;
  1003.     }
  1004.   return (char *) p;
  1005. }
  1006.  
  1007.  
  1008. /* Function to evaluate the plural expression and return an index value.  */
  1009. static unsigned long int
  1010. internal_function
  1011. plural_eval (pexp, n)
  1012.      struct expression *pexp;
  1013.      unsigned long int n;
  1014. {
  1015.   switch (pexp->nargs)
  1016.     {
  1017.     case 0:
  1018.       switch (pexp->operation)
  1019.     {
  1020.     case var:
  1021.       return n;
  1022.     case num:
  1023.       return pexp->val.num;
  1024.     default:
  1025.       break;
  1026.     }
  1027.       /* NOTREACHED */
  1028.       break;
  1029.     case 1:
  1030.       {
  1031.     /* pexp->operation must be lnot.  */
  1032.     unsigned long int arg = plural_eval (pexp->val.args[0], n);
  1033.     return ! arg;
  1034.       }
  1035.     case 2:
  1036.       {
  1037.     unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
  1038.     if (pexp->operation == lor)
  1039.       return leftarg || plural_eval (pexp->val.args[1], n);
  1040.     else if (pexp->operation == land)
  1041.       return leftarg && plural_eval (pexp->val.args[1], n);
  1042.     else
  1043.       {
  1044.         unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
  1045.  
  1046.         switch (pexp->operation)
  1047.           {
  1048.           case mult:
  1049.         return leftarg * rightarg;
  1050.           case divide:
  1051.         return leftarg / rightarg;
  1052.           case module:
  1053.         return leftarg % rightarg;
  1054.           case plus:
  1055.         return leftarg + rightarg;
  1056.           case minus:
  1057.         return leftarg - rightarg;
  1058.           case less_than:
  1059.         return leftarg < rightarg;
  1060.           case greater_than:
  1061.         return leftarg > rightarg;
  1062.           case less_or_equal:
  1063.         return leftarg <= rightarg;
  1064.           case greater_or_equal:
  1065.         return leftarg >= rightarg;
  1066.           case equal:
  1067.         return leftarg == rightarg;
  1068.           case not_equal:
  1069.         return leftarg != rightarg;
  1070.           default:
  1071.         break;
  1072.           }
  1073.       }
  1074.     /* NOTREACHED */
  1075.     break;
  1076.       }
  1077.     case 3:
  1078.       {
  1079.     /* pexp->operation must be qmop.  */
  1080.     unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
  1081.     return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
  1082.       }
  1083.     }
  1084.   /* NOTREACHED */
  1085.   return 0;
  1086. }
  1087.  
  1088.  
  1089. /* Return string representation of locale CATEGORY.  */
  1090. static const char *
  1091. internal_function
  1092. category_to_name (category)
  1093.      int category;
  1094. {
  1095.   const char *retval;
  1096.  
  1097.   switch (category)
  1098.   {
  1099. #ifdef LC_COLLATE
  1100.   case LC_COLLATE:
  1101.     retval = "LC_COLLATE";
  1102.     break;
  1103. #endif
  1104. #ifdef LC_CTYPE
  1105.   case LC_CTYPE:
  1106.     retval = "LC_CTYPE";
  1107.     break;
  1108. #endif
  1109. #ifdef LC_MONETARY
  1110.   case LC_MONETARY:
  1111.     retval = "LC_MONETARY";
  1112.     break;
  1113. #endif
  1114. #ifdef LC_NUMERIC
  1115.   case LC_NUMERIC:
  1116.     retval = "LC_NUMERIC";
  1117.     break;
  1118. #endif
  1119. #ifdef LC_TIME
  1120.   case LC_TIME:
  1121.     retval = "LC_TIME";
  1122.     break;
  1123. #endif
  1124. #ifdef LC_MESSAGES
  1125.   case LC_MESSAGES:
  1126.     retval = "LC_MESSAGES";
  1127.     break;
  1128. #endif
  1129. #ifdef LC_RESPONSE
  1130.   case LC_RESPONSE:
  1131.     retval = "LC_RESPONSE";
  1132.     break;
  1133. #endif
  1134. #ifdef LC_ALL
  1135.   case LC_ALL:
  1136.     /* This might not make sense but is perhaps better than any other
  1137.        value.  */
  1138.     retval = "LC_ALL";
  1139.     break;
  1140. #endif
  1141.   default:
  1142.     /* If you have a better idea for a default value let me know.  */
  1143.     retval = "LC_XXX";
  1144.   }
  1145.  
  1146.   return retval;
  1147. }
  1148.  
  1149. /* Guess value of current locale from value of the environment variables.  */
  1150. static const char *
  1151. internal_function
  1152. guess_category_value (category, categoryname)
  1153.      int category;
  1154.      const char *categoryname;
  1155. {
  1156.   const char *language;
  1157.   const char *retval;
  1158.  
  1159.   /* The highest priority value is the `LANGUAGE' environment
  1160.      variable.  But we don't use the value if the currently selected
  1161.      locale is the C locale.  This is a GNU extension.  */
  1162.   language = getenv ("LANGUAGE");
  1163.   if (language != NULL && language[0] == '\0')
  1164.     language = NULL;
  1165.  
  1166.   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
  1167.      `LC_xxx', and `LANG'.  On some systems this can be done by the
  1168.      `setlocale' function itself.  */
  1169. #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
  1170.   retval = setlocale (category, NULL);
  1171. #else
  1172.   /* Setting of LC_ALL overwrites all other.  */
  1173.   retval = getenv ("LC_ALL");
  1174.   if (retval == NULL || retval[0] == '\0')
  1175.     {
  1176.       /* Next comes the name of the desired category.  */
  1177.       retval = getenv (categoryname);
  1178.       if (retval == NULL || retval[0] == '\0')
  1179.     {
  1180.       /* Last possibility is the LANG environment variable.  */
  1181.       retval = getenv ("LANG");
  1182.       if (retval == NULL || retval[0] == '\0')
  1183.         /* We use C as the default domain.  POSIX says this is
  1184.            implementation defined.  */
  1185.         return "C";
  1186.     }
  1187.     }
  1188. #endif
  1189.  
  1190.   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
  1191. }
  1192.  
  1193. /* @@ begin of epilog @@ */
  1194.  
  1195. /* We don't want libintl.a to depend on any other library.  So we
  1196.    avoid the non-standard function stpcpy.  In GNU C Library this
  1197.    function is available, though.  Also allow the symbol HAVE_STPCPY
  1198.    to be defined.  */
  1199. #if !_LIBC && !HAVE_STPCPY
  1200. static char *
  1201. stpcpy (dest, src)
  1202.      char *dest;
  1203.      const char *src;
  1204. {
  1205.   while ((*dest++ = *src++) != '\0')
  1206.     /* Do nothing. */ ;
  1207.   return dest - 1;
  1208. }
  1209. #endif
  1210.  
  1211. #if !_LIBC && !HAVE_MEMPCPY
  1212. static void *
  1213. mempcpy (dest, src, n)
  1214.      void *dest;
  1215.      const void *src;
  1216.      size_t n;
  1217. {
  1218.   return (void *) ((char *) memcpy (dest, src, n) + n);
  1219. }
  1220. #endif
  1221.  
  1222.  
  1223. #ifdef _LIBC
  1224. /* If we want to free all resources we have to do some work at
  1225.    program's end.  */
  1226. static void __attribute__ ((unused))
  1227. free_mem (void)
  1228. {
  1229.   void *old;
  1230.  
  1231.   while (_nl_domain_bindings != NULL)
  1232.     {
  1233.       struct binding *oldp = _nl_domain_bindings;
  1234.       _nl_domain_bindings = _nl_domain_bindings->next;
  1235.       if (oldp->dirname != _nl_default_dirname)
  1236.     /* Yes, this is a pointer comparison.  */
  1237.     free (oldp->dirname);
  1238.       free (oldp->codeset);
  1239.       free (oldp);
  1240.     }
  1241.  
  1242.   if (_nl_current_default_domain != _nl_default_default_domain)
  1243.     /* Yes, again a pointer comparison.  */
  1244.     free ((char *) _nl_current_default_domain);
  1245.  
  1246.   /* Remove the search tree with the known translations.  */
  1247.   __tdestroy (root, free);
  1248.   root = NULL;
  1249.  
  1250.   while (transmem_list != NULL)
  1251.     {
  1252.       old = transmem_list;
  1253.       transmem_list = transmem_list->next;
  1254.       free (old);
  1255.     }
  1256. }
  1257.  
  1258. text_set_element (__libc_subfreeres, free_mem);
  1259. #endif
  1260.